package flib;

import flib.SplitArea.Pair;
import importExport.SVGText;

import java.util.Collections;
import java.util.Vector;

import simpleGeom.Bounds2D;

import simpleGeom.HasPos2D;
import simpleGeom.HasPos3D;
import simpleGeom.Triangulator;
import simpleGeom.Vec2D;

public class Room extends FlibFace {
	public int id;

	Vector<Room> children = new Vector<Room>();

	Vector<EdgeSegment> segments;

	public boolean ispublic;
	public boolean checked;
	SVGText label;
	Split split;
	public int seg1;
	public int seg2;
	public float relPos1;
	public float relPos2;
	public boolean it;
	public boolean cold;

	Vector<FlibHEdge> innerRooms = new Vector<FlibHEdge>();

	public void setPts(Vector<FlibHEdge> hEdges) {
		FlibHEdge hEdge = null;
		for (int i = 0; i < hEdges.size(); i++) {
			hEdge = hEdges.get(i);
			hEdge.attach();
		}
		this.setHEdge(hEdge.getSym());
	}

	public boolean isSteps() {
		return steps;
	}

	public void setSteps(boolean steps) {
		this.steps = steps;
	}

	public void collectAllLeaves(Vector<Room> leaves) {
		if (children.size() == 0) {
			leaves.add(this);
			return;
		}
		for (int i = 0; i < children.size(); i++) {
			Room sA = children.get(i);
			sA.collectAllLeaves(leaves);
		}
	}

	public void initCornerPts() {
		Vector<FlibHENode> nodes = this.getFaceNodes();
		for (int i = 0; i < nodes.size(); i++) {
			int i1 = i;
			int i2 = (i + 1) % nodes.size();
			int i3 = (i + 2) % nodes.size();
			FlibHENode p1 = nodes.get(i1);
			FlibHENode p2 = nodes.get(i2);
			FlibHENode p3 = nodes.get(i3);
			float angle = Vec2D.getAngleBetween(p1, p2, p3);
			if (angle < Math.PI * 0.8f) {
				NodeData n = (NodeData) p2.getData();
				n.setCorner(true);
			}
		}
	}

	public void setCornerPts() {
		Bounds2D b2d = (Bounds2D) this.getBounds2D();
		float closestD = Float.MAX_VALUE;
		Vec2D corner = new Vec2D(b2d.x1, b2d.y1);
		FlibHEdge closestHEdge = null;
		FlibHEdge hE = this.getHEdge();
		do {
			NodeData nD = (NodeData) hE.getOrg().getData();
			if (nD.isCorner()) {
				float cD = hE.getOrg().dist(corner);
				if (cD < closestD) {
					closestHEdge = hE;
					closestD = cD;
				}
			}
			hE = hE.getNext();
		} while (hE != this.getHEdge());
		// closestHEdge=hE;
		hE = closestHEdge;
		// hE=this.getHEdge();
		segments = new Vector<EdgeSegment>();
		do {
			NodeData nD = (NodeData) hE.getOrg().getData();
			if (nD.isCorner()) {
				EdgeSegment seg = new EdgeSegment();
				seg.hEdge = hE;
				segments.add(seg);
				// sammeln.
			}
			hE = hE.getNext();
		} while (hE != closestHEdge);

	}

	public boolean contains(Split split) {
		int id = 0;
		// how to detect a real split...
		Vector<HasPos2D> splitPts = split.getPts();

		int i1 = -1;
		int i2 = -1;

		// contains...
		// genau zwei punkte im ring.
		// beide punkte mit abstand im Ring

		Vector<FlibHENode> nodes = this.getFaceNodes();
		for (int i = 0; i < splitPts.size(); i++) {
			FlibHENode p = (FlibHENode) splitPts.get(i);
			int cI = nodes.indexOf(p);
			if (cI >= 0) {
				id++;
				if (i1 < 0) {
					i1 = cI;
				} else if (i2 < 0) {
					i2 = cI;
				} else
					return false;// mehr als 2 punkte
			}

		}
		if (id != 2)
			return false;
		if (((i1 + 1) % nodes.size()) == i2)
			return false;
		if (((i2 + 1) % nodes.size()) == i1)
			return false;

		return true;
	}

	public Vector<Room> split(int seg1, int seg2, float relPos1, float relPos2) {
		setCornerPts();
		if (seg1 >= segments.size() || seg2 >= segments.size()) {
			System.out.println("too much");
		}

		EdgeSegment segE1 = segments.get(seg1 % segments.size());// %segments.size()
		FlibHENode n1 = segE1.getNode(relPos1);
		EdgeSegment segE2 = segments.get(seg2 % segments.size());// %segments.size()
		FlibHENode n2 = segE2.getNode(relPos2);
		NodeData nd = new NodeData();
		nd.corner = true;
		n1.data = nd;
		NodeData nd2 = new NodeData();
		nd2.corner = true;
		n2.data = nd2;

		FlibHEdge hEdge1 = new FlibHEdge(n1, n2);
		hEdge1.attach();

		Room room1 = new Room();
		room1.setHEdge(hEdge1);
		hEdge1.setFaceToAll(room1);

		Room room2 = new Room();
		room2.setHEdge(hEdge1.getSym());
		hEdge1.getSym().setFaceToAll(room1);

		Vector<Room> rooms = new Vector<Room>();
		rooms.add(room1);
		rooms.add(room2);
		room1.setCornerPts();
		room2.setCornerPts();
		children.add(room1);
		children.add(room2);

		System.out.println("s1: " + room1.segments.size());
		System.out.println("s2: " + room2.segments.size());
		return rooms;
	}

	public Vector<Room> split(Split split) {
		setCornerPts();
		Vector<FlibHENode> nodes = this.getFaceNodes();
		Vector<HasPos2D> splitpts = split.getPts();
		int i1 = -1;
		int i2 = -1;
		for (int i = 0; i < splitpts.size(); i++) {
			FlibHENode p = (FlibHENode) splitpts.get(i);
			for (int j = 0; j < segments.size(); j++) {
				EdgeSegment seg = segments.get(j);
				Vector<FlibHENode> segPts = seg.getNodes();
				int cI = segPts.indexOf(p);
				if (cI >= 0) {
					if (i1 < 0) {
						i1 = i;
						seg1 = j;
						relPos1 = seg.getLength(p) / seg.getLength();
					} else {
						i2 = i;
						seg2 = j;
						relPos2 = seg.getLength(p) / seg.getLength();
						i = splitpts.size();
						break;
					}
				}
			}
		}

		for (int i = i1; i < i2; i++) {
			FlibHEdge hEdge = split.hEdges.get(i);
			hEdge.attach();
		}
		FlibHEdge hEdge1 = split.hEdges.get(i1);
		FlibHENode sN1 = (FlibHENode) splitpts.get(i1);
		FlibHENode sN2 = (FlibHENode) splitpts.get(i2);
		NodeData nD = new NodeData();
		nD.corner = true;
		NodeData nD2 = new NodeData();
		nD2.corner = true;
		sN1.data = nD;
		sN2.data = nD2;
		Room room1 = new Room();
		room1.setHEdge(hEdge1);
		hEdge1.setFaceToAll(room1);
		Room room2 = new Room();
		room2.setHEdge(hEdge1.getSym());
		hEdge1.getSym().setFaceToAll(room1);

		Vector<Room> rooms = new Vector<Room>();
		rooms.add(room1);
		rooms.add(room2);
		room1.setCornerPts();
		room2.setCornerPts();
		children.add(room1);
		children.add(room2);
		this.split = split;
		System.out.println("seg1: " + seg1 + " seg2: " + seg2 + " rel1 "
				+ relPos1 + " rel2 " + relPos2);
		return rooms;
	}

	public Vector<HasPos2D[]> calcTriangles() {
		Vector<FlibHENode> nodes = simpliFiedOutline();
		Vector<FlibHENode> indnodes = new Vector<FlibHENode>();
		for (int j = 0; j < nodes.size(); j++) {
			FlibHENode n = nodes.get(j);
			if (indnodes.contains(n)) {
				FlibHENode newN = new FlibHENode(n.x, n.y);
				indnodes.add(newN);
			} else {
				indnodes.add(n);
			}
		}
		if (indnodes.size() > 3) {
			Triangulator tri = new Triangulator(indnodes);
			tri.triangulate();
			return tri.triangles;
		}
		return null;
	}

	public boolean isCold() {
		if (type == null)
			return cold;
		return !type.isWarm();
	}

	public void setCold(boolean cold) {
		this.cold = cold;
	}

	public boolean isPublic() {
		if (type == null)
			return ispublic;
		return type.isPublic();
	}

	public void setPublic(boolean ispublic) {
		this.ispublic = ispublic;
	}

}
